package org.cloudie.docs.editor.client.serialization;

import java.util.ArrayList;
import java.util.HashMap;

import org.cloudie.docs.editor.client.Preferences;
import org.cloudie.docs.editor.client.commands.Command;
import org.cloudie.docs.editor.client.commands.generic.BrowserOpenCommand;
import org.cloudie.docs.editor.client.commands.generic.DesktopConfigureCommand;
import org.cloudie.docs.editor.client.commands.generic.ExistingDocumentOpenCommand;
import org.cloudie.docs.editor.client.commands.generic.ExplorerWindowOpenFolderCommand;
import org.cloudie.docs.editor.client.commands.generic.ExplorerWindowOpenVirtualFolderCommand;
import org.cloudie.docs.editor.client.commands.generic.FeedEntryOpenCommand;
import org.cloudie.docs.editor.client.commands.generic.NativeAlertCommand;
import org.cloudie.docs.editor.client.commands.generic.SystemNotImplementedCommand;
import org.cloudie.docs.editor.client.commands.generic.VirtualEntryAddCommand;
import org.cloudie.docs.editor.client.commands.generic.VirtualEntryFolderAddCommand;
import org.cloudie.docs.editor.client.commands.generic.VirtualEntryTrashAddCommand;
import org.cloudie.docs.editor.client.commands.generic.WindowAddCommand;
import org.cloudie.docs.editor.client.commands.generic.WindowRestoreCommand;
import org.cloudie.docs.editor.client.events.CommandEvent;
import org.cloudie.docs.editor.client.events.CommandHandler;
import org.cloudie.docs.editor.client.events.HasCommandHandlers;
import org.cloudie.docs.editor.client.storage.apps.AppSystemEntry;
import org.cloudie.docs.editor.client.storage.items.FolderVirtualSystemEntry;
import org.cloudie.docs.editor.client.storage.items.ShortcutVirtualSystemEntry;
import org.cloudie.docs.editor.client.storage.items.TrashVirtualSystemEntry;
import org.cloudie.docs.editor.client.storage.items.VirtualSystemEntry;
import org.cloudie.docs.editor.client.windows.GenericWindow.WindowContents;

import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;

public class Serializer implements HasCommandHandlers {

  private HandlerManager manager;
	  
  public Serializer() {
    manager = new HandlerManager(this);
  }

  private String joinTsvRow(String... values) {
	String s = "";
	int l = values.length - 1;
	for (int i=0; i<values.length; i++) {
	  if (values[i] == null) {
		s += "null";
	  } else {
		s += values[i].replace("\n", "\\n").replace("\t", "");
	  }
	  if (i != l) {
		s += "\t";
	  }
	}
	return s + "\n";
  }
  
  private String[] splitTsvRow(String row) {
	String[] values = row.split("\t");
	for (int i=0; i< values.length; i++) {
	  if (values[i].equals("null")) {
		values[i] = null;
	  } else {
		values[i] = values[i].replace("\\n", "\n");
	  }
	}
	return values;
  }
  
  public String toCsv(Preferences prefs, ArrayList<VirtualSystemEntry> iconEntries,
	  ArrayList<AppSystemEntry> appEntries) {
	String csv = "";
	csv += joinTsvRow("client", "cloudie");
	csv += joinTsvRow("version", "1.0");
	csv += joinTsvRow("preference", "backgroundColor", prefs.getBackgroundColor());
	csv += joinTsvRow("preference", "backgroundPosition", prefs.getBackgroundPosition());
	csv += joinTsvRow("preference", "backgroundRepeat", prefs.getBackgroundRepeat());
	csv += joinTsvRow("preference", "backgroundImage", prefs.getBackgroundImage());
	csv += joinTsvRow("preference", "iconTextColor", prefs.getIconTextColor());
	csv += joinTsvRow("preference", "iconBackgroundColor", prefs.getIconBackgroundColor());
	for (AppSystemEntry entry : appEntries) {
	  csv += joinTsvRow("window", entry.getId(), entry.getLabel(), entry.getContentType(), entry.getContentValue(),
	    String.valueOf(entry.getX()), String.valueOf(entry.getY()),
	    String.valueOf(entry.getWidth()), String.valueOf(entry.getHeight()));
	}
	for (VirtualSystemEntry entry : iconEntries) {
	  if (entry instanceof ShortcutVirtualSystemEntry) {
		ShortcutVirtualSystemEntry shortcut = (ShortcutVirtualSystemEntry) entry;
		Command action = shortcut.getAction();
		if (action != null) {
		  if (action instanceof BrowserOpenCommand) {
			BrowserOpenCommand cmd = (BrowserOpenCommand) action;
			csv += joinTsvRow("action", "browserOpen", shortcut.getId(), cmd.getUrl(), cmd.getName());
		  } else if (action instanceof ExplorerWindowOpenVirtualFolderCommand) {
			ExplorerWindowOpenVirtualFolderCommand cmd =
				(ExplorerWindowOpenVirtualFolderCommand) action;
			csv += joinTsvRow("action", "explorerWindowOpenVirtualFolder", shortcut.getId(),
				cmd.getFolderId());
		  } else if (action instanceof ExplorerWindowOpenFolderCommand) {
			ExplorerWindowOpenFolderCommand cmd =
				(ExplorerWindowOpenFolderCommand) action;
			csv += joinTsvRow("action", "explorerWindowOpenFolder", shortcut.getId(),
				cmd.getFolderName());
		  } else if (action instanceof FeedEntryOpenCommand) {
			FeedEntryOpenCommand cmd = (FeedEntryOpenCommand) action;
			csv += joinTsvRow("action", "feedEntryOpen", cmd.getType(), shortcut.getId(),
				cmd.getEntryId());
		  } else if (action instanceof NativeAlertCommand) {
			NativeAlertCommand cmd = (NativeAlertCommand) action;
			csv += joinTsvRow("action", "nativeAlert", shortcut.getId(),
				cmd.getMessage());
		  } else if (action instanceof ExistingDocumentOpenCommand) {
			csv += joinTsvRow("action", "existingDocumentOpen", shortcut.getId());
		  } else if (action instanceof WindowRestoreCommand) {
			WindowRestoreCommand cmd = (WindowRestoreCommand) action;
			csv += joinTsvRow("action", "windowRestore", shortcut.getId(), cmd.getWindowId(), cmd.getTitle(),
			    cmd.getContents().getType().name(), cmd.getContents().getValue(),
			    String.valueOf(cmd.getX()), String.valueOf(cmd.getY()),
			    String.valueOf(cmd.getWidth()), String.valueOf(cmd.getHeight()));
		  }
		}
	  }
	}
	for (VirtualSystemEntry entry : iconEntries) {
	  if (entry instanceof FolderVirtualSystemEntry) {
		FolderVirtualSystemEntry folderEntry = (FolderVirtualSystemEntry) entry;
	    csv += joinTsvRow("folder", folderEntry.getId(), folderEntry.getLabel(), folderEntry.getImage(),
	    	folderEntry.getParent(), String.valueOf(folderEntry.getX()), String.valueOf(folderEntry.getY()),
	    	String.valueOf(folderEntry.getTray()));
	  } else if (entry instanceof ShortcutVirtualSystemEntry) {
		ShortcutVirtualSystemEntry shortcutEntry = (ShortcutVirtualSystemEntry) entry;
		csv += joinTsvRow("shortcut", shortcutEntry.getId(), shortcutEntry.getLabel(), shortcutEntry.getImage(),
			shortcutEntry.getTooltip(), shortcutEntry.getParent(),
			String.valueOf(shortcutEntry.getX()), String.valueOf(shortcutEntry.getY()),
	    	String.valueOf(shortcutEntry.getTray()));
	  } else if (entry instanceof TrashVirtualSystemEntry) {
		TrashVirtualSystemEntry trashEntry = (TrashVirtualSystemEntry) entry;
		csv += joinTsvRow("trash", trashEntry.getId(), trashEntry.getLabel(),
			String.valueOf(trashEntry.getX()), String.valueOf(trashEntry.getY()),
	    	String.valueOf(trashEntry.getTray()));
		
	  }
	}
	return csv;
  }
	  
  public void fromCsv(String csv) {
	HashMap<String, Command> actions = new HashMap<String, Command>();
	Preferences prefs = new Preferences();
	String[] rows = csv.split("\n");
	for (String row : rows) {
	  String[] cols = splitTsvRow(row);
	  if (cols.length < 1) continue;
	  String type = cols[0];
	  if (type.equals("preference")) {
	    if (cols.length < 3) continue;
	    String name = cols[1];
	    String value = cols[2];
	    if (name.equals("backgroundColor")) prefs.setBackgroundColor(value);
	    else if (name.equals("backgroundPosition")) prefs.setBackgroundPosition(value);
	    else if (name.equals("backgroundRepeat")) prefs.setBackgroundRepeat(value);
	    else if (name.equals("backgroundImage")) prefs.setBackgroundImage(value);
	    else if (name.equals("iconTextColor")) prefs.setIconTextColor(value);
	    else if (name.equals("iconBackgroundColor")) prefs.setIconBackgroundColor(value);
	  } else if (type.equals("window")) {
		if (cols.length < 9) continue;
		WindowContents wc = new WindowContents(WindowContents.ContentType.valueOf(cols[3]), cols[4]);
		WindowAddCommand cmd = new WindowAddCommand(cols[1], cols[2], wc,
		    Integer.valueOf(cols[5]), Integer.valueOf(cols[6]),
		    Integer.valueOf(cols[7]), Integer.valueOf(cols[8]));
		CommandEvent.fire(this, cmd);
	  } else if (type.equals("action")) {
		if (cols.length < 3) continue;
		String name = cols[1];
		String id = cols[2];
		if (name.equals("browserOpen")) {
		  if (cols.length < 5) continue;
		  BrowserOpenCommand cmd = new BrowserOpenCommand(cols[3], cols[4]);
		  actions.put(id, cmd);
		} else if (name.equals("explorerWindowOpenVirtualFolder")) {
		  if (cols.length < 4) continue;
		  ExplorerWindowOpenVirtualFolderCommand cmd =
			  new ExplorerWindowOpenVirtualFolderCommand(cols[3]);
		  actions.put(id, cmd);
		} else if (name.equals("explorerWindowOpenFolder")) {
		  if (cols.length < 4) continue;
		  ExplorerWindowOpenFolderCommand cmd =
			  new ExplorerWindowOpenFolderCommand(cols[3], true);
		  actions.put(id, cmd);
		} else if (name.equals("feedEntryOpen")) {
		  if (cols.length < 5) continue;
		  FeedEntryOpenCommand cmd =
			  new FeedEntryOpenCommand(cols[3], cols[4]);
		  actions.put(id, cmd);
		} else if (name.equals("nativeAlert")) {
		  if (cols.length < 4) continue;
		  NativeAlertCommand cmd =
			  new NativeAlertCommand(cols[3]);
		  actions.put(id, cmd);
		} else if (name.equals("existingDocumentOpen")) {
		  if (cols.length < 3) continue;
		  ExistingDocumentOpenCommand cmd =
			  new ExistingDocumentOpenCommand();
		  actions.put(id, cmd);
		} else if (name.equals("windowRestore")) {
		  if (cols.length < 11) continue;
		  WindowContents wc = new WindowContents(WindowContents.ContentType.valueOf(cols[5]), cols[6]);
		  WindowRestoreCommand cmd = new WindowRestoreCommand(id, cols[3], cols[4], wc,
		    Integer.valueOf(cols[7]), Integer.valueOf(cols[8]),
		    Integer.valueOf(cols[9]), Integer.valueOf(cols[10]));
		  actions.put(id, cmd);
		}
	  } else if (type.equals("folder")) {
		if (cols.length < 8) continue;
		VirtualEntryFolderAddCommand cmd = new VirtualEntryFolderAddCommand(
		    cols[1], cols[2], cols[3], cols[4], Integer.parseInt(cols[5]), Integer.parseInt(cols[6]),
		    Integer.parseInt(cols[7]));
		CommandEvent.fire(this, cmd);
	  } else if (type.equals("shortcut")) {
		if (cols.length < 9) continue;
		String id = cols[1];
		Command action = new SystemNotImplementedCommand();
		if (actions.containsKey(id)) action = actions.get(id);
		VirtualEntryAddCommand cmd = new VirtualEntryAddCommand(
			id, cols[2], cols[3], cols[4], cols[5], Integer.parseInt(cols[6]),
			Integer.parseInt(cols[7]), Integer.parseInt(cols[8]), action);
		CommandEvent.fire(this, cmd);
	  } else if (type.equals("trash")) {
		if (cols.length < 6) continue;
		VirtualEntryTrashAddCommand cmd = new VirtualEntryTrashAddCommand(
	        cols[1], cols[2], true, Integer.parseInt(cols[3]), Integer.parseInt(cols[4]),
	        Integer.parseInt(cols[5]));
		CommandEvent.fire(this, cmd);
	  }
	}
	DesktopConfigureCommand cmd = new DesktopConfigureCommand(
	    prefs.getBackgroundColor(), prefs.getBackgroundImage(),
	    prefs.getBackgroundPosition(), prefs.getBackgroundRepeat(),
	    prefs.getIconTextColor(), prefs.getIconBackgroundColor());
	CommandEvent.fire(this, cmd);
  }

  @Override
  public HandlerRegistration addCommandHandler(CommandHandler handler) {
	return manager.addHandler(CommandEvent.getType(), handler);
  }
  
  @Override
  public void fireEvent(GwtEvent<?> event) {
	manager.fireEvent(event);
  }
  
}
